package course.p3_arraysSort;

import course.p3_arraysSort.exa01_maopao.MaoPaoSort;
import course.p3_arraysSort.exa02_insertSort.InsertSort;
import course.p3_arraysSort.exa03_shellSort.ShellSort;
import course.p3_arraysSort.exa04_quickSort.QuickSort;
import course.p3_arraysSort.exa05_mergeSort.MergeSort;

import java.io.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.logging.Logger;

@SuppressWarnings({"unchecked"})
public class SortUtil {

    public static final String QUICK = "quick";
    public static final String SHELL = "shell";
    public static final String MAOPAO = "maopao";
    public static final String INSERT = "insert";
    public static final String MERGE = "merge";
    public static final String HEAP = "heap";
    public static final String COUNT = "count";//计数排序
    public static final String BASENUM = "baseNum";// 基数排序
    public static final String BUCKET = "bucket";// 桶排序

    /**
     * 排序方法调用
     * @param in 需排序的数组
     * @param sortType maoPao--冒泡排序  insert--插入排序
     *                 shell--希尔排序   quick--快速排序
     *                 merge--归并排序   heap--堆排序
     *                 counting--计数排序
     * @return 返回排序后的结果
     */
    public static <T extends Comparable<T>> Object[] sort(T[] in,String sortType) {
        if(sortType.equals(MAOPAO)){
            return MaoPaoSort.sort(in);
        }
        if(sortType.equals(INSERT)){
            return InsertSort.sort(in);
        }
        if(sortType.equals(SHELL)){
            return ShellSort.sort(in,in.length);
        }
        if(sortType.equals(QUICK)){
            return QuickSort.quickSort(in,0,in.length-1);
        }
        if(sortType.equals(MERGE)){
            return MergeSort.mergeSort(in,0,in.length-1);
        }
//        if(sortType.equals(COUNT)){
//            return SortCore.CountingSort(in,0,in.length-1);
//        }
//        if(sortType.equals("heap")){
//            return new SortCore.Heap().Heapsort(null,in,in.length);
//        }

        return null;
    }

    /**
     * 随机数组生成器，此方法可以生成普通数字类型,浮动数字类型 字符串类型的数组
     * 推荐使用：整数类型 Integer 浮动数类型 Double 字符串类型 String
     * @param type 元素类型
     * @param count 数组大小
     * @param <T> 泛型类型
     * @return 返回生成后的数组
     */
    public static <T extends Comparable<T>> Object[] makeRandomArray(T type,Integer count) throws Exception {
        Object[] result=new Object[count];
        Class<?> cl=type.getClass();
        Constructor<?>[] constructors=cl.getDeclaredConstructors();
        Constructor<T> constructor=null;
        for(Constructor<?> constructor1:constructors){
            Class<?>[] types = constructor1.getParameterTypes();
            if(types.length==1&&types[0]==String.class){
                constructor= (Constructor<T>) constructor1;
                break;
            }
        }
        if(constructor==null){
            throw new Exception("此类型不支持生成随机类型");
        }
        for(int i=0;i<count;i++){
            String emuStr=null;
            double emu = 0;
            if(type.getClass()==String.class){
                int strLength=(int)(Math.random()*10);
                if(strLength<1){
                    strLength=1;
                }
                StringBuilder strBul=new StringBuilder();
                for(int j=0;j<strLength;j++){
                    int num=(int)(Math.random()*122);
                    while (num<97){
                        num=(int)(Math.random()*122);
                    }
                    char letter=(char) num;
                    strBul.append(letter);
                }
                emuStr=strBul.toString();
            }else{
                emu=(Math.random()*1000);
                emuStr= Double.toString(emu);
            }
            try{
                result[i]=constructor.newInstance(emuStr);
            }catch (Exception e){
                int emuInt=(int)emu;
                emuStr=Integer.toString(emuInt);
                result[i]=constructor.newInstance(emuStr);
            }
        }
        return  result;
    }

    /**
     * 测方法用于测试排序方法
     * @param obj 需要测试的类型
     * @return 返回测试结果
     */
    public static <T extends Comparable<T>> boolean sortTest(T obj,String type,int count,String testType){
        Object[] testResults = new Object[0];
        long start1,end1,start2,end2;
        try{
            testResults = SortUtil.makeRandomArray(obj,count);
            Object[] sourceArray = Arrays.copyOf(testResults,testResults.length);
            Object[] arraySort = new Object[testResults.length];
            T[] result= (T[]) Array.newInstance(obj.getClass(),testResults.length);
            int i=0;
            for(Object object:testResults){
                File file=new File("temp.ser");
                if(file.exists()){
                    boolean flag=file.delete();
                }
                FileOutputStream fileOut = new FileOutputStream("temp.ser");//定义文件字节输出流，源为temp
                ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);//定义对象字节输出流
                objectOut.writeObject(object);//将对象序列化信息写入源中
                objectOut.close();//关闭对象输出流
                FileInputStream fileIn = new FileInputStream("temp.ser");//定义文件输入流，源为temp
                ObjectInputStream objectIn = new ObjectInputStream(fileIn);//定义对象字节输入流
                Object target = (T)objectIn.readObject();//将源中的对象读出得到object的克隆
                objectIn.close();//关闭对象输入流
                arraySort[i]=target;
                result[i]=(T)object;
                i++;
            }
            start1=System.currentTimeMillis();
            testResults = SortUtil.sort(result,type);
            end1=System.currentTimeMillis();
            start2=System.currentTimeMillis();
            Arrays.sort(arraySort);
            end2=System.currentTimeMillis();
            if(testType.equals("timeTest")){
                Logger.getGlobal().info("自研排序方法"+type+"所需要的时间为"+(end1-start1)+"ms");
                Logger.getGlobal().info("Jdk排序方法排序所需要的时间为"+(end2-start2)+"ms");
            }
            for(int n=0;n<testResults.length;n++){
                if(!testResults[n].equals(arraySort[n])){
                    System.out.println(Arrays.toString(sourceArray));
                    System.out.println(Arrays.toString(testResults));
                    return false;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

    public static void main(String[] args) {
        for(;;){
            boolean isRight = sortTest(1,MAOPAO,1000,"timeTest");
            if(isRight) {
            System.out.println("正确的算法！！");
            }else{
                break;
            }

        }

    }
}
